'''
认证服务，提供用户登录、令牌管理等功能
'''
import jwt
import datetime
from flask import g, request, current_app
import functools
import hashlib
import os

# 从环境变量获取JWT密钥，不存在时使用默认值
JWT_SECRET = os.environ.get('JWT_SECRET', 'linetest-secure-jwt-key-12345')
JWT_ALGORITHM = 'HS256'
# 令牌过期时间可配置，默认为7天
JWT_EXPIRATION_DELTA = datetime.timedelta(days=int(os.environ.get('JWT_EXPIRATION_DAYS', '7')))

# 记录JWT配置信息
print(f"[认证服务] JWT配置已加载，有效期: {JWT_EXPIRATION_DELTA.days}天")

def generate_password_hash(password):
    """生成密码哈希"""
    # 实际生产中应使用更安全的密码哈希算法，如bcrypt
    return hashlib.sha256(password.encode()).hexdigest()

def verify_password(password, hashed_password):
    """验证密码"""
    return generate_password_hash(password) == hashed_password

def authenticate_user(username, password, tenant_code):
    """验证用户凭证"""
    conn = g.db
    cursor = conn.cursor()
    
    # 查询租户ID
    cursor.execute(
        "SELECT id FROM tenants WHERE code = %s AND status = 'active'",
        (tenant_code,)
    )
    tenant = cursor.fetchone()
    
    if not tenant:
        return None
    
    tenant_id = tenant[0]
    
    # 查询用户
    cursor.execute(
        "SELECT id, username, password, role, tenant_id FROM users WHERE username = %s AND tenant_id = %s AND status = 'active'",
        (username, tenant_id)
    )
    user = cursor.fetchone()
    
    if not user or not verify_password(password, user[2]):
        return None
    
    # 更新最后登录时间
    cursor.execute(
        "UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = %s",
        (user[0],)
    )
    conn.commit()
    
    # 返回用户信息
    return {
        'id': user[0],
        'username': user[1],
        'role': user[3],
        'tenant_id': user[4],
        'tenant_code': tenant_code
    }

def generate_token(user):
    """生成JWT令牌"""
    payload = {
        'user_id': user['id'],
        'username': user['username'],
        'role': user['role'],
        'tenant_id': user['tenant_id'],
        'tenant_code': user['tenant_code'],
        'exp': datetime.datetime.utcnow() + JWT_EXPIRATION_DELTA
    }
    return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)

def decode_token(token):
    """解码JWT令牌"""
    if not token:
        print("[认证服务] 令牌为空")
        return None
        
    # 打印令牌的前10个字符用于调试（不要打印完整令牌，避免安全问题）
    token_preview = token[:10] + "..." if len(token) > 10 else token
    print(f"[认证服务] 尝试解码令牌: {token_preview}")
    
    try:
        payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
        print(f"[认证服务] 令牌解码成功，用户: {payload.get('username')}, 角色: {payload.get('role')}")
        return payload
    except jwt.ExpiredSignatureError:
        # 令牌已过期
        print("[认证服务] 令牌已过期")
        return None
    except jwt.InvalidTokenError as e:
        # 无效令牌
        print(f"[认证服务] 无效令牌: {str(e)}")
        return None
    except Exception as e:
        # 其他异常
        print(f"[认证服务] 令牌解码时发生未知错误: {str(e)}")
        return None

def get_current_user():
    """从请求中获取当前用户"""
    auth_header = request.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return None
    
    token = auth_header.split(' ')[1]
    payload = decode_token(token)
    
    if not payload:
        return None
    
    return payload

def verify_tenant_permission(tenant_id, user_id):
    """
    验证用户是否有权限访问特定租户的资源
    
    Args:
        tenant_id: 租户ID
        user_id: 用户ID
        
    Returns:
        bool: 是否有权限
    """
    if not tenant_id or not user_id:
        return False
        
    conn = g.db
    cursor = conn.cursor()
    
    # 查询用户所属租户
    cursor.execute(
        "SELECT tenant_id FROM users WHERE id = %s AND status = 'active'", 
        (user_id,)
    )
    user_tenant = cursor.fetchone()
    
    if not user_tenant:
        return False
    
    # 验证用户所属租户是否与目标租户一致
    return str(user_tenant[0]) == str(tenant_id)

def auth_required(f):
    """
    认证验证装饰器，验证用户是否已登录
    并在g对象中设置用户ID和权限信息
    """
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        auth_header = request.headers.get('Authorization')
        if not auth_header or not auth_header.startswith('Bearer '):
            return {'error': '未提供有效的认证信息'}, 401
        
        token = auth_header.split(' ')[1]
        payload = decode_token(token)
        
        if not payload:
            return {'error': '认证令牌已过期或无效'}, 401
        
        # 设置全局用户信息
        g.user_id = payload.get('user_id')
        g.username = payload.get('username')
        g.role = payload.get('role')
        g.tenant_id = payload.get('tenant_id')
        
        return f(*args, **kwargs)
    return decorated

def login_required(f):
    """登录验证装饰器"""
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        # 记录访问的端点路径
        print(f"[认证服务] 访问需要认证的端点: {request.path}")
        
        # 获取用户信息
        user = get_current_user()
        
        # 用户信息不存在（未认证）
        if not user:
            # 检查是否有认证头
            auth_header = request.headers.get('Authorization')
            error_detail = "认证头不存在"
            
            if auth_header:
                if not auth_header.startswith('Bearer '):
                    error_detail = "认证头格式不正确，需要 Bearer token"
                else:
                    token = auth_header.split(' ')[1]
                    # 简单验证token是否为空
                    if not token:
                        error_detail = "令牌为空"
                    elif token == "undefined" or token == "null":
                        error_detail = "令牌值无效(undefined/null)"
                    else:
                        error_detail = "令牌无效或已过期"
            
            print(f"[认证服务] 认证失败: {error_detail}")
            
            return {
                'status': 'error', 
                'message': '未授权访问', 
                'error_detail': error_detail
            }, 401
        
        # 认证通过，设置当前用户信息
        g.current_user = user
        return f(*args, **kwargs)
    
    return decorated

def tenant_required(f):
    """租户验证装饰器，确保用户只能访问自己租户的数据"""
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        user = get_current_user()
        if not user:
            return {'status': 'error', 'message': '未授权访问'}, 401
        
        g.current_user = user
        
        # 如果请求包含项目ID，验证项目是否属于用户的租户
        if 'project_id' in kwargs:
            conn = g.db
            cursor = conn.cursor()
            cursor.execute(
                "SELECT tenant_id FROM projects WHERE id = %s",
                (kwargs['project_id'],)
            )
            project = cursor.fetchone()
            if not project or project[0] != user['tenant_id']:
                return {'status': 'error', 'message': '无权访问该资源'}, 403
        
        return f(*args, **kwargs)
    return decorated

def admin_required(f):
    """管理员权限验证装饰器"""
    @functools.wraps(f)
    def decorated(*args, **kwargs):
        user = get_current_user()
        if not user or user['role'] != 'admin':
            return {'status': 'error', 'message': '需要管理员权限'}, 403
        g.current_user = user
        return f(*args, **kwargs)
    return decorated 